home *** CD-ROM | disk | FTP | other *** search
- /**
- ** sipp - SImple Polygon Processor
- **
- ** A general 3d graphic package
- **
- ** Copyright Equivalent Software HB 1992
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 1, or any later version.
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- ** You can receive a copy of the GNU General Public License from the
- ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- **/
-
- /**
- ** pixel.c - Functions that handle the pixel buffer
- **/
-
-
- #include <sipp.h>
- #include <smalloc.h>
- #include <pixel.h>
-
-
- /*
- * Background color.
- */
- Color sipp_bgcol;
-
-
- /*
- * Entry in a position in the pixel buffer.
- */
- typedef struct {
- Color color;
- Color opacity;
- double depth;
- int next;
- } Pixel_info;
-
-
- static int pixbuf_size; /* Current size of pixel buffer */
- static int size_delta; /* How much to realloc each time */
- static Pixel_info *pixbuf = 0; /* The actual pixel buffer */
- static int first_free; /* First free Pixel_info in the buffer */
-
-
-
- /*
- * Initialize the pixel buffer.
- */
- void
- pixels_setup(init_size)
- int init_size;
- {
- if (pixbuf != 0) {
- sfree(pixbuf); /* Just in case */
- }
-
- pixbuf = (Pixel_info *)scalloc(init_size, sizeof(Pixel_info));
- pixbuf_size = init_size;
- pixels_reinit();
- size_delta = init_size / 2;
- }
-
-
- /*
- * Free memory used by pixel_buffer.
- */
- void
- pixels_free()
- {
- sfree(pixbuf);
- pixbuf = 0;
- }
-
-
- /*
- * Renitialize the free_list.
- */
- void
- pixels_reinit()
- {
- first_free = 0;
- }
-
-
- /*
- * Allocate a Pixel_info struct from the free list.
- * Realloc a larger pixbuf if needed.
- */
- static int
- pixel_alloc()
- {
- if (first_free == pixbuf_size) {
- pixbuf_size += size_delta;
- pixbuf = (Pixel_info *)srealloc(pixbuf,
- pixbuf_size * sizeof(Pixel_info));
- }
-
- pixbuf[first_free].next = -1;
- first_free++;
- return (first_free - 1);
- }
-
-
- /*
- * Check if a polygon at DEPTH is possibly visible in PIXEL
- */
- bool
- pixel_visible(depth, pixel)
- double depth;
- int pixel;
- {
- Color opacity_sum;
-
- opacity_sum.red = 0.0;
- opacity_sum.grn = 0.0;
- opacity_sum.blu = 0.0;
-
- while (pixel != -1) {
- if (depth < pixbuf[pixel].depth) {
- return TRUE;
- }
- opacity_sum.red += pixbuf[pixel].opacity.red;
- opacity_sum.grn += pixbuf[pixel].opacity.grn;
- opacity_sum.blu += pixbuf[pixel].opacity.blu;
- if (opacity_sum.red < 1.0 || opacity_sum.grn < 1.0
- || opacity_sum.grn < 1.0) {
- pixel = pixbuf[pixel].next;
- } else {
- return FALSE;
- }
- }
-
- return TRUE;
- }
-
-
- /*
- * Create a new Pixel_info struct containing DEPTH, COLOR and OPACITY and
- * insert it into PIXEL.
- */
- int
- pixel_insert(pixel, depth, color, opacity)
- int pixel;
- double depth;
- Color *color;
- Color *opacity;
- {
- int pixref1;
- int pixref2;
- int tmp;
-
- tmp = pixel_alloc();
- pixbuf[tmp].depth = depth;
- pixbuf[tmp].color = *color;
- pixbuf[tmp].opacity = *opacity;
-
- if (pixel == -1) {
- return tmp;
- } else if (depth < pixbuf[pixel].depth) {
- pixbuf[tmp].next = pixel;
- return tmp;
- } else {
- pixref1 = pixel;
- pixref2 = pixbuf[pixel].next;
- while (pixref2 != -1 && pixbuf[pixref2].depth < depth) {
- pixref1 = pixref2;
- pixref2 = pixbuf[pixref2].next;
- }
- pixbuf[pixref1].next = tmp;
- pixbuf[tmp].next = pixref2;
- return pixel;
- }
- }
-
-
- /*
- * Sum the resulting color in a pixel and store it
- * in the first Pixel_info in the list (if there is one).
- * Return a pointer to this color, or NULL if there is no color.
- */
- Color *
- pixel_collect(pixel)
- int pixel;
- {
- Color result;
- Color frac;
- Color opacity_sum;
- int pixref;
- bool pixel_full;
-
- result.red = result.grn = result.blu = 0.0;
- opacity_sum.red = opacity_sum.grn = opacity_sum.blu = 0.0;
-
- pixref = pixel;
- pixel_full = FALSE;
-
- while (pixref != -1) {
- frac.red = pixbuf[pixref].opacity.red;
- if (frac.red + opacity_sum.red > 1.0) {
- frac.red = 1.0 - opacity_sum.red;
- }
- frac.grn = pixbuf[pixref].opacity.grn;
- if (frac.grn + opacity_sum.grn > 1.0) {
- frac.grn = 1.0 - opacity_sum.grn;
- }
- frac.blu = pixbuf[pixref].opacity.blu;
- if (frac.blu + opacity_sum.blu > 1.0) {
- frac.blu = 1.0 - opacity_sum.blu;
- }
- result.red += frac.red * pixbuf[pixref].color.red;
- result.grn += frac.grn * pixbuf[pixref].color.grn;
- result.blu += frac.blu * pixbuf[pixref].color.blu;
- opacity_sum.red += frac.red;
- opacity_sum.grn += frac.grn;
- opacity_sum.blu += frac.blu;
- if (opacity_sum.red >= 1.0 && opacity_sum.grn >= 1.0
- && opacity_sum.blu >= 1.0) {
- pixel_full = TRUE;
- break;
- }
- pixref = pixbuf[pixref].next;
- }
-
- if (pixel != -1) {
- if (!pixel_full) {
- result.red += ((opacity_sum.red >= 1.0)
- ? 0.0 : 1.0 - opacity_sum.red) * sipp_bgcol.red;
- result.grn += ((opacity_sum.grn >= 1.0)
- ? 0.0 : 1.0 - opacity_sum.grn) * sipp_bgcol.grn;
- result.blu += ((opacity_sum.blu >= 1.0)
- ? 0.0 : 1.0 - opacity_sum.blu) * sipp_bgcol.blu;
- }
- pixbuf[pixel].color = result;
- return &pixbuf[pixel].color;
- } else {
- return &sipp_bgcol;
- }
- }
-